<template>
  <div class="w-full h-full flex flex-row">
    <div class="h-full w-0 grow flex flex-col">
      <price-prediction :current-price="priceCurrent" />
      <div class="w-full h-0 grow">
        <ticker-chart ref="tickerChart"></ticker-chart>
      </div>
    </div>
    <div class="p-1 bg-gray-50 border-gray-100 border-l">
      <a-row class="bg-white border p-1 rounded border-gray-200 mb-2">
        <a-col :span="16">
          <a-statistic title="余额" :value="accountBalanceBase.toFixed(8)" />
        </a-col>
        <a-col :span="8" class="text-right">
          <a-statistic title="收益" v-if="accountBalanceBase.greaterThan(accountBalanceNow)"
            :value="`-${accountBalanceBase.minus(accountBalanceNow).toFixed(6)}`"
            :value-style="{color:'#cf1322'}"
          ></a-statistic>
          <a-statistic title="收益" v-else-if="accountBalanceBase.lessThan(accountBalanceNow)"
            :value="`+${accountBalanceNow.minus(accountBalanceBase).toFixed(6)}`"
            :value-style="{color:'#3f8600'}"
          ></a-statistic>
          <a-statistic title="收益" v-else :value="0" />
        </a-col>
      </a-row>

      <div class="bg-white border p-1 rounded border-gray-200 mb-2">
        <a-form label-align="left" :label-col="{span:8}" :wrapper-col="{span:16}">
          <a-form-item label="产品" class="!mb-1">
            <a-select
              v-model:value="options.instId"
              :show-search="true"
              :filter-option="instrumentOptionFilter"
              :disabled="status !== 'idle'"
              @change="actionInstrumentChange"
            >
              <a-select-option v-for="instrument of instruments" :key="instrument.instId" :value="instrument.instId"
              >{{ instrument.instId }}</a-select-option>
            </a-select>
          </a-form-item>

          <a-form-item label="基础价格" class="!mb-1">
            <a-input-number class="w-full" :value="priceBase.toFixed(8)" :disabled="status !== 'idle'">
              <template #addonAfter><redo-outlined @click="actionPriceBaseRefresh" /></template>
            </a-input-number>
          </a-form-item>

          <a-form-item label="基价自动更新" class="!mb-1">
            <a-checkbox v-model:checked="options.priceBaseAutoUpdate"
              :disabled="status !== 'idle'"
            ></a-checkbox>
          </a-form-item>

          <a-form-item label="持有量" class="!mb-1">
            <a-input-number class="!w-full" :value="quantity.toFixed(8)" disabled />
          </a-form-item>

          <a-form-item label="操作状态" class="!mb-1">
            <a-select class="!w-full" :value="status" disabled :show-arrow="false">
              <a-select-option value="idle">空闲</a-select-option>
              <a-select-option value="buying">买入中</a-select-option>
              <a-select-option value="ready">准备卖出</a-select-option>
              <a-select-option value="selling">卖出中</a-select-option>
            </a-select>
          </a-form-item>

          <a-form-item label="自动卖出" class="!mb-1">
            <a-checkbox v-model:checked="options.autoSellEnable"
              :disabled="status !== 'idle'"
            ></a-checkbox>
          </a-form-item>

          <a-form-item label="自动买入" class="!mb-1">
            <a-checkbox v-model:checked="options.autoBuyEnable"
              :disabled="status !== 'idle'"
            ></a-checkbox>
          </a-form-item>
        </a-form>
      </div>

      <!-- 买入 -->
      <order-buy ref="buyer"
        v-if="priceBase.greaterThan(0)"
        v-model:price-bought="priceBought"
        :disabled="status !== 'idle'"
        :inst-id="options.instId"
        :base-price="priceBase"
        :current-price="priceCurrent"
        @start="actionBuyStart"
        @success="actionBuySuccess"
        @failed="actionBuyFailed"
      ></order-buy>

      <!-- 卖出 -->
      <order-sell ref="seller"
        v-if="priceBought.greaterThan(0)"
        :disabled="status !== 'ready'"
        :inst-id="options.instId"
        :base-price="priceBase"
        :bought-price="priceBought"
        :current-price="priceCurrent"
        :quantity="quantity"
        @start="actionSellStart"
        @success="actionSellSuccess"
        @failed="actionSellFailed"
      ></order-sell>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, watch, provide, h, nextTick } from 'vue'
import { RedoOutlined, LoadingOutlined } from '@ant-design/icons-vue';
import Decimal from 'decimal.js';
import OkxWsPublicService from './OkxWsPublicService.js';
import TickerChart from './TickerChart.vue';
import OkxRestService from './OkxRestService.js';
import OrderBuy from './OrderBuy.vue';
import OrderSell from './OrderSell.vue';
import Common from './Common.js';
import PricePrediction from './PricePrediction.vue';
/** @var {Object} */
const priceCurrent = ref(new Decimal(0));
/** @var {number} */
const priceBase = ref(new Decimal(0));
/** @var {number} */
const priceBought = ref(new Decimal(0));
/** @var {TickerChart} */
const tickerChart = ref(null);
/** @var {Array} */
const instruments = ref([]);
/** @var {Number} */
const quantity = ref(new Decimal(0));
/** @var {String} */
const status = ref('idle');
/** @var {number} */
const accountBalanceBase = ref(new Decimal(0));
/** @var {number} */
const accountBalanceNow = ref(new Decimal(0));
/** @var {OrderSell} */
const seller = ref(null);
/** @var {OrderBuy} */
const buyer = ref(null);
/** @var {Object} */
const options = ref({
    instId : 'BTC-USDT',
    priceBaseAutoUpdate : true,
    autoSellEnable : false,
    autoBuyEnable : false,
});
/** @var {String} */
let activeInstId = 'BTC-USDT';
// on mounted
onMounted(mounted);
// provide ticker chart
provide('tickerChart', tickerChart);
// handle options change
watch(options, handleOptionsChange, {deep:true});

// on mounted
async function mounted() {
    let loading = Common.loading();

    let optionsData = localStorage.getItem('app-options');
    if ( null !== optionsData ) {
        options.value = JSON.parse(optionsData);
        activeInstId = options.value.instId;
    }

    let publicService = OkxWsPublicService.getInstance();
    await publicService.start();
    await publicService.subscribe('tickers', {instId:options.value.instId}, handleChanelTickersOnData);

    let restService = OkxRestService.getInstance();
    let instrumentList = await restService.instrumentList();
    instrumentList = instrumentList.filter(item => item.quoteCcy == 'USDT');
    instruments.value = instrumentList;

    let accountBalance = await restService.accountBalanceGet('USDT');
    accountBalanceBase.value = new Decimal(accountBalance.availBal);
    accountBalanceNow.value = new Decimal(accountBalance.availBal);

    await quantityRefresh();
    loading.destroy();
}

// 持仓数量刷新
async function quantityRefresh() {
    let restService = OkxRestService.getInstance();
    let activeInstrument = instruments.value.find(item => item.instId == options.value.instId);
    let baseCcy = activeInstrument.baseCcy;
    let balance = await restService.accountBalanceGet(baseCcy);
    if ( null === balance ) {
        quantity.value = new Decimal(0);
    } else {
        quantity.value = new Decimal(balance.availBal);
    }

    let instrument = await restService.instrumentGet(options.value.instId);
    if ( quantity.value.lessThanOrEqualTo(instrument.minSz) ) {
        quantity.value = new Decimal(0);
    }
}

// handle options change
function handleOptionsChange() {
    let optionsData = JSON.stringify(options.value);
    localStorage.setItem('app-options', optionsData);
}

// handle chanel tickers on data
function handleChanelTickersOnData( data, args ) {
    priceCurrent.value = new Decimal(data[0].last);
    if ( 'idle' === status.value ) {
        if ( priceBase.value.equals(0) || true === options.value.priceBaseAutoUpdate ) {
            priceBase.value = priceCurrent.value;
        }
    }
    tickerChart.value.appendData(priceCurrent.value.toString());
}

// instrument option filter
function instrumentOptionFilter( input, option ) {
    if (input == '') {
        return true;
    }
    input = input.toLowerCase();
    let value = option.value.toLowerCase();
    return value.startsWith(input);
}

// handle instrument change
async function actionInstrumentChange() {
    let loading = Common.loading();

    let publicService = OkxWsPublicService.getInstance();
    await publicService.unsubscribe('tickers', {instId:activeInstId});

    priceBase.value = new Decimal(0);
    priceBought.value = new Decimal(0);
    quantity.value = new Decimal(0);
    priceCurrent.value = new Decimal(0);
    status.value = 'idle';
    await nextTick();

    tickerChart.value.reset();

    await quantityRefresh();
    await publicService.subscribe('tickers', {instId:options.value.instId}, handleChanelTickersOnData);
    activeInstId = options.value.instId;
    loading.destroy();
}

// action price base refresh
function actionPriceBaseRefresh() {
    priceBase.value = priceCurrent.value;
}

// action on bought
function actionBuyStart( price ) {
    priceBase.value = price;
    status.value = 'buying';
    tickerChart.value.markLineSet('base', price.toString(), {name:'基价', color:'gray'});
}

// action on buy finish
async function actionBuySuccess( price ) {
    priceBought.value = price;

    await quantityRefresh();
    if ( quantity.value.lessThanOrEqualTo(0) ) {
        status.value = 'idle';
        return;
    }

    status.value = 'ready';
    if ( true === options.value.autoSellEnable ) {
        seller.value.sell();
    }
}

// action on buy failed
async function actionBuyFailed() {
    status.value = 'idle';
    tickerChart.value.markLineSet('base', null);
}

// action on sell start
function actionSellStart() {
    status.value = 'selling';
}

// action on sold
async function actionSellSuccess( number ) {
    let restService = OkxRestService.getInstance();

    // 更新持仓数量
    await quantityRefresh();

    // 更新余额
    let accountBalance = await restService.accountBalanceGet('USDT');
    accountBalanceNow.value = new Decimal(accountBalance.availBal);

    // 更新操作状态
    if ( quantity.value.greaterThan(0) ) {
        status.value = 'ready';
    } else {
        tickerChart.value.markLineSet('base', null);
        status.value = 'idle';
        if ( true === options.value.autoBuyEnable ) {
            buyer.value.autoBuy();
        }
    }
}

// action on sell failed
async function actionSellFailed() {
    status.value = 'ready';
    tickerChart.value.markLineSet('base', null);
}
</script>

